﻿namespace JavaScript8000
{
    using System;
    using System.Windows.Forms;

    using JavaScript8000.Common;
    using JavaScript8000.Parser;
    using JavaScript8000.Scaner;

    /// <summary>
    /// The parser form.
    /// </summary>
    public partial class ParserForm : Form
    {
        #region Constants and Fields

        /// <summary>
        /// Results of scan.
        /// </summary>
        private readonly ScanResults scanResults;

        /// <summary>
        /// Results of parse operation.
        /// </summary>
        private ParseResult result;

        #endregion

        #region Constructors and Destructors

        /// <summary>
        /// Initializes a new instance of the <see cref="ParserForm"/> class.
        /// </summary>
        /// <param name="scResults">
        /// The s results.
        /// </param>
        public ParserForm(ScanResults scResults)
        {
            this.InitializeComponent();

            if (scResults == null)
            {
                throw new ArgumentNullException("ScanResults shouldn't be null!");
            }

            this.scanResults = scResults;

            this.tokenTextBox.Text = scResults.GetStringOfTokensList();
        }

        #endregion

        #region Methods

        /// <summary>
        /// Collapse tree view.
        /// </summary>
        /// <param name="sender">
        /// The source of the event.
        /// </param>
        /// <param name="e">
        /// The <see cref="System.EventArgs"/> instance containing the event data.
        /// </param>
        private void CloseAllToolStripMenuItemClick(object sender, EventArgs e)
        {
            this.treeView1.CollapseAll();
        }

        /// <summary>
        /// Expand tree view.
        /// </summary>
        /// <param name="sender">
        /// The source of the event.
        /// </param>
        /// <param name="e">
        /// The <see cref="System.EventArgs"/> instance containing the event data.
        /// </param>
        private void OpenAllToolStripMenuItemClick(object sender, EventArgs e)
        {
            this.treeView1.ExpandAll();
        }

        /// <summary>
        /// Parses the grammar tree to tree which we can display in tree view control.
        /// </summary>
        /// <param name="tree">
        /// The tree.
        /// </param>
        /// <returns>
        /// Root of tree.
        /// </returns>
        private TreeNode ParseTree(GrammarNode tree)
        {
            var node = new TreeNode();

            if (tree.Token == null)
            {
                node.Text = tree.Value;
                foreach (GrammarNode child in tree.Children)
                {
                    node.Nodes.Add(this.ParseTree(child));
                }
            }
            else
            {
                if (tree.Token.Code == SystemTokens.IdCode || tree.Token.Code == SystemTokens.NumericLiteralCode || tree.Token.Code == SystemTokens.BoolLiteralCode || tree.Token.Code == SystemTokens.NullLiteral
                    || tree.Token.Code == SystemTokens.StringLiteralCode)
                {
                    node.Text = this.scanResults.UserTokens.GetByUserCode(tree.Token.UserCode);
                }
                else
                {
                    node.Text = SystemTokens.GetName(tree.Token.Code);
                }
            }

            return node;
        }

        /// <summary>
        /// Show grammar form.
        /// </summary>
        /// <param name="sender">
        /// The source of the event.
        /// </param>
        /// <param name="e">
        /// The <see cref="System.EventArgs"/> instance containing the event data.
        /// </param>
        private void ShowGrammarToolStripMenuItemClick(object sender, EventArgs e)
        {
            BrainFuck form = Grammar.GetForm();
            if (!form.Visible)
            {
                form.Show();
            }
        }

        /// <summary>
        /// Simplify grammar tree and display it in tree view.
        /// </summary>
        /// <param name="sender">
        /// The source of the event.
        /// </param>
        /// <param name="e">
        /// The <see cref="System.EventArgs"/> instance containing the event data.
        /// </param>
        private void SimplifyToolStripMenuItemClick(object sender, EventArgs e)
        {
            this.result.GrammarTree = this.SimplifyTree(this.result.GrammarTree);
            this.treeView1.Nodes.Clear();
            this.treeView1.Nodes.Add(this.ParseTree(this.result.GrammarTree));
            this.treeView1.ExpandAll();

            this.executeProgrammToolStripMenuItem.Enabled = !this.result.WasError;
        }

        /// <summary>
        /// Simplifies grammar tree.
        /// Remove useless nodes.
        /// </summary>
        /// <param name="node">
        /// The node.
        /// </param>
        /// <returns>
        /// Root node of simplified tree.
        /// </returns>
        private GrammarNode SimplifyTree(GrammarNode node)
        {
            if (node.Token == null)
            {
                if (node.Children.Count == 1)
                {
                    return this.SimplifyTree(node.Children[0]);
                }
                else
                {
                    for (int i = 0; i < node.Children.Count; i++)
                    {
                        node.Children[i] = this.SimplifyTree(node.Children[i]);
                    }
                }
            }

            return node;
        }

        /// <summary>
        /// Handles the Click event of the startToolStripMenuItem control.
        /// </summary>
        /// <param name="sender">
        /// The source of the event.
        /// </param>
        /// <param name="e">
        /// The <see cref="System.EventArgs"/> instance containing the event data.
        /// </param>
        private void StartToolStripMenuItemClick(object sender, EventArgs e)
        {
            this.result = Parser.Parser.Parse(this.scanResults);
            this.treeView1.Nodes.Clear();
            this.treeView1.Nodes.Add(this.ParseTree(this.result.GrammarTree));
            this.treeView1.ExpandAll();
            this.errorTextBox.Text = this.result.ErrorMessage;
            this.executeProgrammToolStripMenuItem.Enabled = false;
            this.simplifyToolStripMenuItem.Enabled = this.treeView1.Nodes.Count > 0;
        }

        #endregion

        /// <summary>
        /// Handles the Click event of the executeProgrammToolStripMenuItem control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void ExecuteProgrammToolStripMenuItemClick(object sender, EventArgs e)
        {
            // Show magic window.
            MagicForm form = new MagicForm(this.scanResults, this.result.GrammarTree);
            form.Closed += delegate
            {
                this.Show();
                this.executeProgrammToolStripMenuItem.Enabled = false;
                this.simplifyToolStripMenuItem.Enabled = false;
                this.treeView1.Nodes.Clear();
            };

            form.Show(this);
            this.Hide();
        }
    }
}